package com.dtx.strategy;

/**
 * Hand类是表示猜拳游戏中的"手势"的类。在该类的内部,用int表示说出的手势,其中0表示石头,1表示剪刀,2表示布,
 * 并将值保存在handValue字段中。
 * 我们只需要3个Hand类的实例。在程序的开始,创建这3个实例,并将它们保存在hand数组中。
 * Hand类的实例可以通过使用类方法getHand来获取。只要将表示手势的值作为参数传递给getHand方法,它就会将手势的值所对应的
 * Hand类的实例返回给我们。这也是一种Singleton模式。
 * isStrongerThan方法和isWeakerThan方法用于判断猜拳结果。例如,如果有手势hand1和手势hand2,那么可以像下面这样判断猜拳结果。
 *      hand1.isStrongerThan(hand2)
 *      hand1.isWeakerThan(hand2)
 * 在该类的内部,实际负责判断猜拳结果的是fight方法,其判断依据是手势的值。
 * 代码中的(this.handValue + 1) % 3 == h.handValue表达式可能会有些难以理解,所以这里稍微说明一下。如果this的手势加1
 * 后是h的手势值(例如,如果this的手势是石头,而h是剪刀,或是this的手势是剪刀,而h是布,或是this的手势是布,而h是石头),
 * 那么判断this获胜。之所以使用"%"运算符进行取余数计算,是希望布(2)加1后,变成石头(0)。
 * 在上面的语句中,出现了this.handValue,这是为了让读者能够注意到它与h.handValue的区别。在程序中,
 * 即使写作(this.handValue + 1) % 3 == h.handValue,意思也是完全一样的。
 * 虽然Hand类会被其他类(Player类,WinningStrategy类,ProbStrategy类)使用,但它并非Strategy模式中的角色。
 */
public class Hand {

    /**
     * 表示石头的值
     */
    public static final int HANDVALUE_GUU = 0;

    /**
     * 表示剪刀的值
     */
    public static final int HANDVALUE_CHO = 1;

    /**
     * 表示布的值
     */
    public static final int HANDVALUE_PAA = 2;

    /**
     * 表示猜拳中3种手势的实例
     */
    public static final  Hand[] hand = {
            new Hand(HANDVALUE_GUU),
            new Hand(HANDVALUE_CHO),
            new Hand(HANDVALUE_PAA)
    };

    /**
     * 表示猜拳中手势所对应的字符串
     */
    private enum Name{

        GUU("石头",0),
        CHO("剪刀",1),
        PAA("布",2);

        String name;

        Integer code;

        Name(String name, Integer code) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        /**
         * 根据code返回Hand手势
         * @param code
         * @return
         */
        public static String getHandByCode(Integer code){
            for (Name value : Name.values()) {
                if (value.code.equals(code)) {
                    return value.getName();
                }
            }
            return null;
        }
    }

    /**
     * 表示猜拳中出的手势的值
     */
    private int handValue;

    private Hand(int handValue) {
        this.handValue = handValue;
    }

    /**
     * 根据手势的值获取其对应的实例
     * @param handValue
     * @return
     */
    public static Hand getHand(int handValue){
        return hand[handValue];
    }

    /**
     * 如果this胜了h则返回true
     * @param h
     * @return
     */
    public boolean isStrongerThan(Hand h){
        return fight(h) == 1;
    }

    /**
     * 如果this输给了h则返回true
     * @param h
     * @return
     */
    public boolean isWeakerThan(Hand h){
        return fight(h) == -1;
    }

    /**
     * 计分: 平0, 胜1, 负 -1
     * @param h
     * @return
     */
    private int fight(Hand h){

        if (this == h) {
            return 0;
        }else if((this.handValue + 1) % 3 == h.handValue){
            return 1;
        }else {
            return -1;
        }
    }

    /**
     * 转换为手势值所对应的字符串
     * @return
     */
    @Override
    public String toString() {
        return Name.getHandByCode(handValue);
    }
}
